package org.gluedom.transport;

import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.gluedom.data.Immutable;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.MapMaker;

class MemoryTransportFactory implements TransportFactory {
	private final ConcurrentMap<Connection, MemoryTransport> transportMap = new MapMaker()
			.makeMap();
	private final ExecutorService executor = Executors.newCachedThreadPool();

	@Override
	public Transport getInstance(Connection connection) {
		if (!transportMap.containsKey(connection))
			transportMap.putIfAbsent(connection,
					new MemoryTransport(connection));
		return transportMap.get(connection);
	}

	private void sendEvent(final ImmutableList<Immutable> data,
			final SendCallback callback, final Connection connection) {
		executor.execute(new Runnable() {
			@Override
			public void run() {
				((MemoryTransport) getInstance(connection)).received(data,
						callback);
			}
		});
	}

	private class MemoryTransport implements Transport {
		private final Connection connection;
		private ReceiveCallback receive = null;

		public MemoryTransport(Connection connection) {
			this.connection = connection;
		}

		@Override
		public void receive(ReceiveCallback callback) {
			receive = callback;
		}

		public void received(ImmutableList<Immutable> data,
				final SendCallback callback) {
			if (receive == null) {
				executor.execute(new Runnable() {
					@Override
					public void run() {
						callback.doCallback(null);
					}
				});
				return;
			}
			receive.doCallback(data, callback);
		}

		@Override
		public void send(ImmutableList<Immutable> data, SendCallback callback) {
			sendEvent(data, callback, connection);
		}
	}
}
